package com.ghovos.usermangerpgdemo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ghovos.usermangerpgdemo.common.constant.RedisConst;
import com.ghovos.usermangerpgdemo.common.exception.GlobalException;
import com.ghovos.usermangerpgdemo.common.result.GlobalResultEnum;
import com.ghovos.usermangerpgdemo.common.utils.UserInfoJsonUtils;
import com.ghovos.usermangerpgdemo.entity.*;
import com.ghovos.usermangerpgdemo.entity.ext.UserWithRoleIds;
import com.ghovos.usermangerpgdemo.mapper.*;
import com.ghovos.usermangerpgdemo.service.RoleService;
import lombok.AllArgsConstructor;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author EdgarLiu(刘凌峰) <br/>
 * date: 2022/3/18 <br/>
 * time: 上午9:41 <br/>
 * email: EdgarLlf@foxmail.com
 */
@Service
@AllArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, RoleEntity> implements RoleService {
    private final RoleMapper roleMapper;
    private final UserMapper userMapper;
    private final MenuMapper menuMapper;
    private final PermissionMapper permissionMapper;
    private final UserRoleMapper userRoleMapper;
    private final RoleMenuMapper roleMenuMapper;
    private final RolePermissionMapper rolePermissionMapper;
    private final StringRedisTemplate stringRedisTemplate;


    @Override
    public RoleEntity getRoleExtById(Long id) {

        // 1. 获取角色详情
        RoleEntity roleEntity = roleMapper.selectById(id);

        // 2. 获取用户ids
        List<Long> userIdList = userRoleMapper.selectList(
                Wrappers.<UserRoleEntity>lambdaQuery()
                        .eq(UserRoleEntity::getRoleId, id)
        ).stream().map(UserRoleEntity::getUserId).collect(Collectors.toList());

        // 3. 获取用户实体list
        if (!userIdList.isEmpty()) {
            List<UserEntity> userEntities = userMapper.selectList(
                    Wrappers.<UserEntity>lambdaQuery()
                            .in(UserEntity::getId, userIdList)
            );
            roleEntity.setUserEntityList(userEntities);
        }

        // 4. 获取 menu ids
        List<Long> menuIds = roleMenuMapper.selectList(
                Wrappers.<RoleMenuEntity>lambdaQuery()
                        .eq(RoleMenuEntity::getRoleId, id)
        ).stream().map(RoleMenuEntity::getRoleId).collect(Collectors.toList());

        // 5. 根据ids 获取menu列表
        if (!menuIds.isEmpty()) {
            List<MenuEntity> menuEntities = menuMapper.selectList(
                    Wrappers.<MenuEntity>lambdaQuery()
                            .in(MenuEntity::getId, menuIds)
            );
            roleEntity.setMenuEntityList(menuEntities);
        }

        // 6. 获取 menu ids
        List<Long> permissionIds = rolePermissionMapper.selectList(
                Wrappers.<RolePermissionEntity>lambdaQuery()
                        .eq(RolePermissionEntity::getRoleId, id)
        ).stream().map(RolePermissionEntity::getRoleId).collect(Collectors.toList());

        // 7. 根据ids 获取permission列表
        if (!permissionIds.isEmpty()) {
            List<PermissionEntity> menuEntities = permissionMapper.selectList(
                    Wrappers.<PermissionEntity>lambdaQuery()
                            .in(PermissionEntity::getId, permissionIds)
            );
            roleEntity.setPermissionEntityList(menuEntities);
        }
        return roleEntity;
    }

    @Override
    public boolean removeByIdWithOtherEntity(Long id) {
        userRoleMapper.delete(Wrappers.<UserRoleEntity>lambdaQuery()
                .eq(UserRoleEntity::getRoleId, id));
        roleMenuMapper.delete(Wrappers.<RoleMenuEntity>lambdaQuery()
                .eq(RoleMenuEntity::getRoleId, id));
        rolePermissionMapper.delete(Wrappers.<RolePermissionEntity>lambdaQuery()
                .eq(RolePermissionEntity::getRoleId, id));

        stringRedisTemplate.delete(RedisConst.ROLE + id);

        return this.removeById(id);
    }

    @Override
    public boolean addUserList(Long roleId, List<Long> ids) {
        for (Long userId : ids) {
            try {
                int insert = userRoleMapper.insert(new UserRoleEntity() {{
                    setUserId(userId);
                    setRoleId(roleId);
                }});
                if (insert > 0) {
                    this.refreshUser(userId);
                }
            }catch (DuplicateKeyException e){
                e.printStackTrace();
                throw new GlobalException(GlobalResultEnum.SQL_UN_ERROR);
            }
        }
        return true;
    }

    @Override
    public boolean deleteUserList(Long roleId, List<Long> ids) {
        LambdaQueryWrapper<UserRoleEntity> userRoleWrapper = Wrappers.<UserRoleEntity>lambdaQuery()
                .eq(UserRoleEntity::getRoleId, roleId)
                .in(UserRoleEntity::getUserId, ids);


        // 1. 先 删除用户权限
        int delete = userRoleMapper.delete(userRoleWrapper);
        if (delete > 0) {
            ids.forEach(this::refreshUser);
        }
        return delete > 0;
    }

    @Override
    public boolean addMenuList(Long roleId, List<Long> ids) {
        for (Long menuId : ids) {
            roleMenuMapper.insert(new RoleMenuEntity() {{
                setMenuId(menuId);
                setRoleId(roleId);
            }});
        }
        return true;
    }

    @Override
    public boolean deleteMenuList(Long roleId, List<Long> ids) {
        LambdaQueryWrapper<RoleMenuEntity> roleMenuWrapper = Wrappers.<RoleMenuEntity>lambdaQuery()
                .eq(RoleMenuEntity::getRoleId, roleId)
                .in(RoleMenuEntity::getMenuId, ids);
        int delete = roleMenuMapper.delete(roleMenuWrapper);
        return delete > 0;
    }

    @Override
    public boolean addPermissionList(Long roleId, List<Long> ids) {
        for (Long permissionId : ids) {
            try{
                rolePermissionMapper.insert(new RolePermissionEntity() {{
                    setPermissionId(permissionId);
                    setRoleId(roleId);
                }});
            }catch (DuplicateKeyException e){
                e.printStackTrace();
                throw new GlobalException(GlobalResultEnum.SQL_UN_ERROR);
            }

        }
        ids.forEach(permissionId -> {
            PermissionEntity permissionEntity = permissionMapper.selectById(permissionId);
            stringRedisTemplate.opsForSet().add(
                    RedisConst.ROLE + roleId,
                    permissionEntity.getUrl()
            );
        });
        return true;
    }

    @Override
    public boolean deletePermissionList(Long roleId, List<Long> ids) {
        LambdaQueryWrapper<RolePermissionEntity> rolePermissionWrapper = Wrappers.<RolePermissionEntity>lambdaQuery()
                .eq(RolePermissionEntity::getRoleId, roleId)
                .in(RolePermissionEntity::getPermissionId, ids);
        ids.forEach(permissionId -> {
            PermissionEntity permissionEntity = permissionMapper.selectById(permissionId);
            stringRedisTemplate.opsForSet().remove(
                    RedisConst.ROLE + roleId,
                    permissionEntity.getUrl()
            );
        });
        int delete = rolePermissionMapper.delete(rolePermissionWrapper);
        return delete > 0;
    }


    /**
     * 刷新用户， 先处理用户信息
     *
     * @param userId 用户id
     */
    private void refreshUser(Long userId) {
        List<UserRoleEntity> userRoleEntities = userRoleMapper.selectList(Wrappers.<UserRoleEntity>lambdaQuery()
                .eq(UserRoleEntity::getUserId, userId));
        if (userRoleEntities != null) {
            List<Long> roleIds = userRoleEntities.stream().distinct().map(UserRoleEntity::getRoleId).collect(Collectors.toList());
            this.refreshUserInRedis(
                    new UserWithRoleIds() {{
                        setRoleIds(roleIds);
                        setId(userId);
                    }}
            );
        }
    }


    /**
     * 刷新用户redis权限， 删除token
     *
     * @param userWithRoleIds 用户信息
     */
    private void refreshUserInRedis(UserWithRoleIds userWithRoleIds) {

        // 获取
        Set<String> tokens = stringRedisTemplate.opsForSet().members(RedisConst.USER_ID + userWithRoleIds.getId());
        if (tokens != null) {
            tokens.forEach(token -> {
                stringRedisTemplate.opsForValue().getAndSet(
                        RedisConst.ALLOW_LIST + token,
                        UserInfoJsonUtils.toJson(userWithRoleIds)
                );
            });
        }
    }

}
